package com.azdebugit.trancation.test;

import com.azdebugit.trancation.test.abstra.CommonServiceImpl;
import com.azdebugit.trancation.test.dao.CompensationMiniDao;
import com.azdebugit.trancation.test.enu.HandleMethodEnum;
import com.azdebugit.trancation.test.enu.StatusEnum;
import com.azdebugit.trancation.test.pojo.CompensationEntity;
import com.azdebugit.trancation.test.service.CompensationService;
import com.azdebugit.trancation.test.util.JsonUtil;
import com.azdebugit.trancation.test.util.ValidateUtils;
import com.fasterxml.jackson.core.type.TypeReference;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

//补偿那块的逻辑实现
@Service
@Transactional
public class CompensationServiceImpl extends CommonServiceImpl implements CompensationService {
    private static final Logger logger = LoggerFactory.getLogger(CompensationServiceImpl.class);
    @Resource
    CompensationMiniDao compensationMiniDao;

    /**
     * 1：定时任务调度的方式
     *
     * @return 处理说明
     */
    @Override
    public String autoRetry() {
        // 1: 查询所有需要重试的记录，数据入库的时候重试次数为0
        StringBuilder stringBuffer = new StringBuilder();
        List<CompensationEntity> list = compensationMiniDao.getRetryList();
        stringBuffer.append("待补偿数据：").append(list.size()).append("条!");
        int successCount = 0;
        int failCount = 0;
        for (CompensationEntity compensationEntity : list) {
            int retryCount = compensationEntity.getRetryCount() + 1;
            compensationEntity.setRetryCount(retryCount);
            try {
                // 调用需要重试的方法
                boolean callStatus = callTargetMethod(compensationEntity);
                // 补偿成功
                if (callStatus) {
                    compensationEntity.setResultMsg("CommonConstants.Public.SUCCESS");
                    compensationEntity.setDataStatus(StatusEnum.StatusEnum_SUCCESS.getCode());
                    successCount++;
                }
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
                compensationEntity.setResultMsg(e.getMessage());
                if (RETRY_LIMIT_COUNT == retryCount) {
                    compensationEntity.setDataStatus(StatusEnum.StatusEnum_FAIL.getCode());
                }
                failCount++;
            }
            this.updateBySqlString(buildUpdateSql(compensationEntity));
        }
        stringBuffer.append("处理成功：").append(successCount).append("条!");
        stringBuffer.append("处理失败：").append(failCount).append("条!");
        return stringBuffer.toString();
    }

    /**
     * 2：人工重试的方式
     *
     * @param id id
     * @return 处理信息
     */
    @Override
    public String manualRetry(Integer id) {
        // 1: 定损需要处理的对象和返回的参数
        CompensationEntity dealObj = null;
        String result = "0";
        try {
            // 2: 根据id查询数据库
            List<CompensationEntity> dealObjList = this.findByProperty(CompensationEntity.class, "id", id);
            ValidateUtils.notEmpty(dealObjList, String.format("根据id：%s,查询返回的对象为空", id));
            dealObj = dealObjList.get(0);
            int retryCount = dealObj.getRetryCount() + 1;
            dealObj.setRetryCount(retryCount);
            dealObj.setType(HandleMethodEnum.MANUAL.getMsg());
            boolean handleResult = callTargetMethod(dealObj);
            if (handleResult) {
                dealObj.setDataStatus(StatusEnum.StatusEnum_SUCCESS.getCode());
            }
        } catch (Exception e) {
            logger.error(e.getCause().getMessage());
            result = e.getCause().getMessage();
        }
        // 3: 操作保存数据，如果依然是失败只改重试的次数，不修改数据的状态
        if (Objects.nonNull(dealObj)) {
            dealObj.setResultMsg(result);
            this.updateBySqlString(buildUpdateSql(dealObj));
        }
        return result;
    }

    /**
     * 构建修改的sql预计
     *
     * @param compensationEntity 实体类对象
     * @return 构建的update sql
     */
    private String buildUpdateSql(CompensationEntity compensationEntity) {
        StringBuilder stringBufferUpdate = new StringBuilder("update a_compensation set dataStatus='");
        stringBufferUpdate.append(compensationEntity.getDataStatus()).append("'").append("CommonConstants.Public.COMMA");
        stringBufferUpdate.append(" retryCount=").append(compensationEntity.getRetryCount()).append("CommonConstants.Public.COMMA");
        stringBufferUpdate.append(" type=").append("\"").append(compensationEntity.getType()).append("\"");
        if (StringUtils.isNotEmpty(compensationEntity.getResultMsg())) {
            stringBufferUpdate.append("CommonConstants.Public.COMMA");
            stringBufferUpdate.append("resultMsg=").append("\"").append(compensationEntity.getResultMsg()).append("\"");
        }
        stringBufferUpdate.append(" where id=").append(compensationEntity.getId());
        return stringBufferUpdate.toString();
    }

    /**
     * 分析数据
     *
     * @return 分析数据的结果
     */
    @Override
    public String analysisData() {
        List<CompensationEntity> allCompensationEntityData = this.getList(CompensationEntity.class);
        StringBuilder dataStr = new StringBuilder(String.format("补偿表数据总量为：%s条！", allCompensationEntityData.size()));
        if (CollectionUtils.isNotEmpty(allCompensationEntityData)) {
            Map<String, List<CompensationEntity>> resultList = allCompensationEntityData.stream().collect(Collectors.groupingBy(CompensationEntity::getDataStatus));
            resultList.forEach((k, v) -> {
                StatusEnum statusEnum = StatusEnum.getStatusEnumByCode(k);
                ValidateUtils.notNull("statusEnum", String.format("补偿表钉钉提醒的时候，查询的数据状态有问题,状态为：%s", k));
                dataStr.append(statusEnum.getMsg()).append(":").append(v.size()).append("条！");
            });
        }
        return dataStr.toString();
    }

    @Override
    public void save(CompensationEntity compensationDO) {

    }

    @Override
    public List<CompensationEntity> findByProperty(Class<CompensationEntity> compensationEntityClass, String busKey, String busKey1) {
        return null;
    }

    public List<CompensationEntity> findByProperty(Class<CompensationEntity> compensationEntityClass, String busKey, int busKey1) {
        return null;
    }

    /**
     * 3： 调用的核心代码
     *
     * @param compensationEntity 补偿对象。
     */
    private boolean callTargetMethod(CompensationEntity compensationEntity) throws Exception {
        // 1: 通过类找到对应的方法
        Method targetMethod = null;
        try {
            Class<?> targetClass = Class.forName(compensationEntity.getClassName());
            ValidateUtils.notNull("targetClass", "补偿时未获取到对应的class bean");
            Method[] methods = targetClass.getMethods();
            for (Method method : methods) {
                // 匹配方法
                if (matchMethod(method, compensationEntity)) {
                    targetMethod = method;
                    break;
                }
            }
        } catch (ClassNotFoundException e) {
            logger.error(e.getMessage(), e);
            throw e;
        }
        try {
            //补偿的目标方法中的参数类型
            ValidateUtils.notNull("targetMethod", "补偿时未获取到对应的bean需要调用的目标方法");
            // 2: 回去方法的参数类型
            Class<?>[] paramTypes = targetMethod.getParameterTypes();
            // 3: 从spring 取的对象
            Object targetObject = null;/*SpringUtil.getBean(StringUtil.firstLowerCase(compensationEntity.getBeanName()));*/
            if (paramTypes.length == 1) {
                // 转成实际类型调用目标方法
                Object obj = JsonUtil.mapper.readValue(compensationEntity.getReqArgs(), paramTypes[0]);
                targetMethod.invoke(targetObject, obj);
            } else if (paramTypes.length > 1) {
                List<Object> objectList = JsonUtil.mapper.readValue(compensationEntity.getReqArgs(), new TypeReference<List<Object>>() {
                });
                Type[] paramTypesReq = targetMethod.getGenericParameterTypes();
                Object[] realParam = new Object[objectList.size()];
                for (int i = 0; i < objectList.size(); i++) {
                    Type paramType = paramTypesReq[i];
                    String param = JsonUtil.mapper.writeValueAsString(objectList.get(i));
                    realParam[i] = JsonUtil.mapper.readValue(param, JsonUtil.mapper.getTypeFactory().constructType(paramType));
                }
                targetMethod.invoke(targetObject, realParam);
            } else {
                logger.error("不支持的参数类型调用");
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw e;
        }
        return true;
    }

    /**
     * 3-1： 寻找类中对应的方法。考虑重载
     *
     * @param method             方法method
     * @param compensationEntity 补偿的类
     * @return 是否匹配上
     */
    private Boolean matchMethod(Method method, CompensationEntity compensationEntity) {
        //  1：先判断方法名，如果类名不匹配，直接返回false
        if (!method.getName().equals(compensationEntity.getMethodName())) {
            return false;
        }
        // 2: 方法名匹配成功后，匹配参数
        Class<?>[] args = method.getParameterTypes();
        if (args.length == 1) {
            return args[0].getName().equals(compensationEntity.getReqArgsType()) && StringUtils.isBlank(compensationEntity.getReqArgsTypeReal());
        } else {
            Class<?>[] classesReq = method.getParameterTypes();
            StringBuilder stringBuffer = new StringBuilder();
            for (Class<?> aClass : classesReq) {
                stringBuffer.append(aClass.getName()).append("CommonConstants.Public.COMMA");
            }
            String multiParamStr = stringBuffer.substring(0, stringBuffer.length() - 1);
            return compensationEntity.getReqArgsTypeReal().equals(multiParamStr);
        }
    }

    @Override
    protected void updateBySqlString(String buildUpdateSql) {

    }

    @Override
    protected List<CompensationEntity> getList(Class<CompensationEntity> compensationEntityClass) {
        return null;
    }
}